﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;


public class HttpModule : MonoBehaviour
{

    public string ip = "127.0.0.1";
    public int port = 5555;
    public HttpListener listener = new HttpListener();
    public bool autoStart = true;
    private bool isExit = false;
    private static HttpModule _instance;
    public static event System.Action<string> onGetEvent;
    public static event System.Action<List<PostValue>> onPostEvent;
    public static HttpModule Instance
    {
        get
        {
            if (_instance == null) throw new System.Exception("单例为空，禁止调用");
            return _instance;
        }
    }
    private void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if (Instance != this)
        {
            Destroy(gameObject);
            return;
        }
    }

    // Use this for initialization
    void Start()
    {
        IPAddress[] ipaddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList;

        for (int i = 0; i < ipaddress.Length; i++)
        {
            if (ipaddress[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                ip = ipaddress[i].ToString();
                break;
            }
        }
        if (autoStart)
            StartServer();
    }
    public void StartServer()
    {
        try
        {
            listener = new HttpListener();
            string address = string.Format("http://{0}:{1}/", ip, port);
            listener.Prefixes.Add(address);

            listener.Start();
            Debug.Log("启动服务器成功:" + address);
            listener.BeginGetContext(ListenCB, null);
        }
        catch (System.Exception ex)
        {
            Debug.LogError("启动服务器失败：" + ex);
        }

    }
    private void ListenCB(System.IAsyncResult ar)
    {
        try
        {
            if (isExit)
                return;
            HttpListenerContext ctx = listener.EndGetContext(ar);
            ctx.Response.StatusCode = 200;
            if (ctx.Request.HttpMethod == "GET")
            {
                System.Threading.ThreadPool.QueueUserWorkItem((_ctx) => { GetHandle((HttpListenerContext)_ctx); }, ctx);
            }
            if (ctx.Request.HttpMethod == "POST")
            {
                System.Threading.ThreadPool.QueueUserWorkItem((_ctx) => { PostHandle((HttpListenerContext)_ctx); }, ctx);
            }
            listener.BeginGetContext(ListenCB, null);
        }
        catch (System.Exception ex)
        {
            Debug.LogError(ex);
        }

    }
    //GET请求
    private void GetHandle(HttpListenerContext ctx)
    {
        string body = Path.GetFileName(ctx.Request.RawUrl);
        if (body == "favicon.ico")
            return;

        if (onGetEvent != null)
            onGetEvent(body);
        //获取RawUrl
        //string rawUrl = Path.GetFileName(ctx.Request.RawUrl);
        //接收Get参数
        //string username = ctx.Request.QueryString["username"];


        //使用Writer输出http响应代码,UTF8格式
        using (StreamWriter sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8))
        {
            sw.WriteLine(string.Format("GET Request  Time is:{0}", System.DateTime.Now));
            sw.Flush();
            sw.Close();
            sw.Dispose();
        }
    }

    public static long GetTimestamp()
    {
        //获取从1970年一月一日0点0分0秒0微妙开始
        return (System.DateTime.UtcNow.Ticks - new System.DateTime(1970, 1, 1, 0, 0, 0, 0).Ticks) / 10000;
    }
    private void PostHandle(HttpListenerContext ctx)
    {
        List<PostValue> form = DecodePost.GetPostValue(ctx);
        if (onPostEvent != null)
            onPostEvent(form);
        using (StreamWriter sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8))
        {
            sw.WriteLine(string.Format("GET Request  Time is:{0}", System.DateTime.Now));
            sw.Flush();
            sw.Close();
            sw.Dispose();
        }
    }

    /// <summary>
    /// Get请求
    /// </summary>
    /// <param name="requestAddress">请求的地址</param>
    /// <param name="paramStr">附加参数</param>
    /// <param name="cb">如果请求成功返回数据，失败返回null</param>
    public static void GetRequest(string requestAddress, string paramStr, System.Action<string> cb)
    {
        Instance.StartCoroutine(Instance._GetRequest(requestAddress, paramStr, cb));
    }
    private IEnumerator _GetRequest(string requestAddress, string paramStr, System.Action<string> cb)
    {
        UnityWebRequest www = UnityWebRequest.Get(requestAddress);
        //www.timeout = UnityWebRequestTimeout;
        yield return www.SendWebRequest();
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogWarning(www.error);
            if (cb != null)
                cb(null);
            yield break;
        }
        cb(www.downloadHandler.text);
    }

    /// <summary>
    /// Post请求
    /// </summary>
    /// <param name="postAddress">请求的地址</param>
    /// <param name="form">附加参数</param>
    /// <param name="cb">如果请求成功返回数据，失败返回null</param>
    public static void PostRequest(string requestAddress, WWWForm form, System.Action<string> cb)
    {
        Instance.StartCoroutine(Instance._PostRequest(requestAddress, form, cb));
    }
    private IEnumerator _PostRequest(string requestAddress, WWWForm form, System.Action<string> cb)
    {
        UnityWebRequest www = UnityWebRequest.Post(requestAddress, form);
        www.uploadHandler.contentType = "multipart/form-data;";
        //www.timeout = UnityWebRequestTimeout;
        yield return www.SendWebRequest();
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogWarning(www.error);
            if (cb != null)
                cb(null);
            yield break;
        }
        if (cb != null)
            cb(www.downloadHandler.text);
    }
    private void OnDestroy()
    {
        isExit = true;
        listener.Close();
        Debug.Log("关闭服务器");
    }
}